const router = require('koa-router')(),
  uuidv4 = require('uuid/v4'),
  aesfn = require('../util/aes_fn'),
  fs = require('fs'),
  path = require('path'),
  config = require('../config/config.json');

const getNowTime = () => {
  const now = new Date();
  return `${now.getFullYear()} 年 ${(now.getMonth() + 1) > 9 ? (now.getMonth() + 1) : '0' + (now.getMonth() + 1)} 月 ${now.getDate() > 9 ? now.getDate() : '0' + now.getDate()} 日`;
}

const blogListData = {
  'blogId': 1,
  'title': 1,
  'category': 1,
  'releaseDate': 1,
  '_id': 0
};

const blogModifyData = {
  'blogId': 1,
  'title': 1,
  'category': 1,
  'markdownContent': 1,
  '_id': 0
};

const blogCategory = {
  'name': 1
}

/* GET admin page. */
router.all('/admin/*', async (ctx, next) => {
  const loginUser = {};

  const userInfo = (await ctx.mongo.db(config.dbname)
    .collection('configs')
    .findOne({ 'primaryKey': 'config' }, {
      projection: {
        "sessionId": 1, "userIp": 1, "pwd": 1, "user": 1
      }
    }));

  loginUser.sessionId = ctx.cookies.get('sessionId'),
    loginUser.ip = aesfn.aesEncrypt(ctx.request.ip, config.aesKey);

  if (loginUser.sessionId !== userInfo.sessionId
    || loginUser.ip !== userInfo.userIp) {
    ctx.redirect('/login');
  } else {
    await next();
  }
});

router.get('/_admin/*', async (ctx, next) => {
  ctx.set('Cache-Control', `max-age=${3 * 60 * 60}`);
  await next();
});

router.get('/login', async (ctx, next) => {
  await ctx.render('admin/login.njk');
})

router.post('/login', async (ctx, next) => {
  const userInfo = (await ctx.mongo.db(config.dbname)
    .collection('configs')
    .findOne({ 'primaryKey': 'config' }, {
      projection: {
        "sessionId": 1, "userIp": 1, "pwd": 1, "user": 1
      }
    }));

  const loginUser = {};
  loginUser.sessionId = ctx.cookies.get('sessionId'),
    loginUser.ip = aesfn.aesEncrypt(ctx.request.ip, config.aesKey),
    loginUser.user = aesfn.aesEncrypt(ctx.request.body.user, config.aesKey),
    loginUser.pwd = aesfn.aesEncrypt(ctx.request.body.pwd, config.aesKey);

  if (loginUser.sessionId === userInfo.sessionId
    && loginUser.ip === userInfo.userIp) {
    ctx.cookies.set('sessionId', userInfo.sessionId, { maxAge: 86400000 * 7 });
    ctx.redirect('/admin/bloglist');
  } else if (loginUser.user === userInfo.user &&
    loginUser.pwd === userInfo.pwd
  ) {
    const newSessionId = aesfn.aesEncrypt(uuidv4(), config.aesKey);
    await ctx.mongo.db(config.dbname)
      .collection('configs')
      .updateOne({ 'primaryKey': 'config' },
        { $set: { 'userIp': loginUser.ip, 'sessionId': newSessionId } });
    ctx.cookies.set('sessionId', newSessionId, { maxAge: 86400000 * 7 });
    ctx.redirect('/admin/bloglist');
  } else {
    ctx.redirect('/login');
  }
});

router.get('/admin', async (ctx, next) => {
  ctx.redirect('/admin/bloglist');
});

router.get('/admin/bloglist', async (ctx, next) => {
  const data = {};
  data.posts = (await ctx.mongo.db(config.dbname).collection('configs').findOne({ 'primaryKey': 'config' })).postMaxId;
  const postsPerPage = (await ctx.mongo.db(config.dbname).collection('configs').findOne({ 'primaryKey': 'config' })).postsPerPage;
  const posts = (await ctx.mongo.db(config.dbname).collection('article').find({}, {
    projection: blogListData
  }).sort({ blogId: -1 }).toArray());

  posts.length > postsPerPage ? data.nextPage = '/admin/bloglist/2' : null;

  data.blogs = posts.slice(0, postsPerPage);
  data.blogs.forEach(item => {
    item.previewUrl = `/admin/preview/${item.blogId}`;
    item.modifyUrl = `/admin/modify/${item.blogId}`;
    item.deleteUrl = `/admin/delete/${item.blogId}`;
  })

  await ctx.render('admin/blog_list.njk', { data });
});

router.get('/admin/bloglist/:page', async (ctx, next) => {
  const curPages = parseInt(ctx.params.page);
  if (curPages < 1 || isNaN(curPages)) {
    await ctx.render('/admin/404.njk');
  } else {
    const data = {};

    data.posts = (await ctx.mongo.db(config.dbname).collection('configs').findOne({ 'primaryKey': 'config' })).postMaxId;
    const postsPerPage = (await ctx.mongo.db(config.dbname).collection('configs').findOne({ 'primaryKey': 'config' })).postsPerPage;
    const posts = (await ctx.mongo.db(config.dbname).collection('article').find({}, {
      projection: blogListData
    }).sort({ blogId: -1 }).toArray());

    const postsLen = posts.length;

    if ((curPages - 1) * postsPerPage > postsLen) {
      await ctx.render('admin/404.njk');
    } else {
      data.blogs = posts.slice((curPages - 1) * postsPerPage, curPages * postsPerPage);
      data.blogs.forEach(item => {
        item.previewUrl = `/admin/preview/${item.blogId}`;
        item.modifyUrl = `/admin/modify/${item.blogId}`;
        item.deleteUrl = `/admin/delete/${item.blogId}`;
      });

      curPages > 1 ? data.previousPage = `/admin/bloglist/${curPages - 1}` : null;
      curPages * postsPerPage < postsLen ? data.nextPage = `/admin/bloglist/${curPages + 1}` : null;

      await ctx.render('admin/blog_list.njk', { data });
    }
  }
});

router.get('/admin/addblog', async (ctx, next) => {
  const data = {};
  data.posts = (await ctx.mongo.db(config.dbname).collection('configs').findOne({ 'primaryKey': 'config' })).postMaxId;
  const categorys = (await ctx.mongo.db(config.dbname).collection('category').find({}, { projection: blogCategory }).toArray());
  data.categorys = categorys.map(item => item.name);
  await ctx.render('admin/add_blog.njk', { data });
});

router.get('/admin/preview/:blogId', async (ctx, next) => {
  const data = await ctx.mongo.db(config.dbname).collection('article').findOne({ 'blogId': parseInt(ctx.params.blogId) });
  if (data) {
    data.posts = (await ctx.mongo.db(config.dbname).collection('configs').findOne({ 'primaryKey': 'config' })).postMaxId;
    data.deleteUrl = `/admin/delete/${ctx.params.blogId}`;
    data.modifyUrl = `/admin/modify/${ctx.params.blogId}`;
    await ctx.render('admin/preview_blog.njk', { data });
  } else {
    await ctx.render('admin/404.njk');
  }
});

router.get('/admin/modify/:blogId', async (ctx, next) => {
  const data = (await ctx.mongo.db(config.dbname).collection('article').findOne({ 'blogId': parseInt(ctx.params.blogId) }, {
    projection: blogModifyData
  }));

  if (data) {
    await ctx.render('admin/add_blog.njk', { data });
  } else {
    await ctx.render('admin/404.njk');
  }
});

router.get('/admin/delete/:blogId', async (ctx, next) => {
  const blogId = parseInt(ctx.params.blogId);
  const category = (await ctx.mongo.db(config.dbname).collection('article').findOne({ 'blogId': blogId })).category;
  await ctx.mongo.db(config.dbname).collection('article').removeOne({ 'blogId': blogId });
  const blogs = (await ctx.mongo.db(config.dbname).collection('category').findOne({ name: category })).blogs;

  let pos = -1,
    blogsLen = blogs.length;

  for (let i = 0; i < blogsLen; i++) {
    if (blogId === blogs[i].blogId) {
      pos = i;
      break;
    }
  }

  blogs.splice(pos, 1);
  await ctx.mongo.db(config.dbname).collection('category').updateOne({ name: category }, { $set: { 'blogs': blogs } });
  await ctx.redirect('/admin/bloglist');
});

router.get('/admin/signout', async (ctx, next) => {
  const newSessionId = aesfn.aesEncrypt(uuidv4(), config.aesKey);

  await ctx.mongo.db(config.dbname)
    .collection('configs')
    .updateOne({ 'primaryKey': 'config' },
      { $set: { 'userIp': 'undefined', 'sessionId': newSessionId } });
  ctx.cookies.set('sessionId', 'undefined');
  ctx.redirect('/');
});

// post blog
router.post('/admin/putblog', async (ctx, next) => {
  const blog = {};
  blog.title = ctx.request.body.title;
  blog.category = ctx.request.body.category;
  blog.markdownContent = ctx.request.body['markdown-content'];
  blog.htmlContent = ctx.request.body['html-content'];
  blog.releaseDate = getNowTime();

  let nowPostId = parseInt(ctx.request.body.blogId);

  if (nowPostId) {
    // relase from modify
    const beforeblog = (await ctx.mongo.db(config.dbname).collection('article').findOne({ 'blogId': nowPostId }));
    const beforeCategory = beforeblog.category,
      beforeTitle = beforeblog.title;
    if (beforeCategory !== blog.category || beforeTitle !== blog.title) {
      // the blog's category has changed
      const beforeblogs = (await ctx.mongo.db(config.dbname).collection('category').findOne({ 'name': beforeCategory })).blogs;

      let pos = -1,
        blogsLen = beforeblogs.length;

      for (let i = 0; i < blogsLen; i++) {
        if (nowPostId === beforeblogs[i].blogId) {
          pos = i;
          break;
        }
      }

      pos > -1 ? beforeblogs.splice(pos, 1) : null;
      await ctx.mongo.db(config.dbname).collection('category').updateOne({ 'name': beforeCategory }, { $set: { 'blogs': beforeblogs } });

      // insert to new category
      let newCategoryArr = (await ctx.mongo.db(config.dbname).collection('category').findOne({ 'name': blog.category }));
      if (newCategoryArr) {
        newCategoryArr.blogs.unshift({ title: blog.title, blogId: nowPostId });
        await ctx.mongo.db(config.dbname).collection('category').updateOne({ 'name': blog.category }, { $set: { 'blogs': newCategoryArr.blogs } });
      } else {
        newCategoryArr = [{ title: blog.title, blogId: nowPostId }];
        await ctx.mongo.db(config.dbname).collection('category').insertOne({ 'name': blog.category, 'blogs': newCategoryArr });
      }
    }
    await ctx.mongo.db(config.dbname)
      .collection('article')
      .updateOne({ 'blogId': nowPostId },
        {
          $set: {
            'title': blog.title,
            'markdownContent': blog.markdownContent,
            'category': blog.category,
            'htmlContent': blog.htmlContent,
            'releaseDate': blog.releaseDate
          }
        });
    ctx.redirect('/admin/preview/' + nowPostId);
  } else {
    await ctx.mongo.db(config.dbname).collection('configs').updateOne({ 'primaryKey': 'config' }, { $inc: { 'postMaxId': 1 } });
    nowPostId = (await ctx.mongo.db(config.dbname).collection('configs').findOne({ 'primaryKey': 'config' })).postMaxId;
    blog.blogId = nowPostId;
    await ctx.mongo.db(config.dbname).collection('article').insertOne(blog);
    let categoryArr = (await ctx.mongo.db(config.dbname).collection('category').findOne({ 'name': blog.category }));
    if (categoryArr) {
      categoryArr.blogs.unshift({ blogId: nowPostId, title: blog.title });
      await ctx.mongo.db(config.dbname).collection('category').updateOne({ 'name': blog.category }, { $set: { 'blogs': categoryArr.blogs } });
    }
    else {
      categoryArr = [{ blogId: nowPostId, title: blog.title }];
      await ctx.mongo.db(config.dbname).collection('category').insertOne({ 'name': blog.category, 'blogs': categoryArr });
    }
    ctx.redirect('/admin/preview/' + nowPostId);
  }
});

// post blog
router.post('/admin/upload_file', async (ctx, next) => {
  const file = ctx.request.files.file
  const ext = file.name.split('.').pop()
  const reader = fs.createReadStream(file.path)
  const reUrl = `/${ext === 'html' ? 'assets' : 'images'}/${uuidv4()}.${ext}`
  const fileName = path.normalize(`${__dirname}/../public${reUrl}`)
  const upStream = fs.createWriteStream(fileName)
  reader.pipe(upStream)

  ctx.status = 200
  ctx.body = reUrl;
  next()
});

module.exports = router;
